package cn.mini.mybatis.mybatis.executor.statementHandler;

import cn.mini.mybatis.mybatis.executor.Executor;
import cn.mini.mybatis.mybatis.executor.resultset.ResultSetHandler;
import cn.mini.mybatis.mybatis.mapping.BoundSql;
import cn.mini.mybatis.mybatis.mapping.MappedStatement;
import cn.mini.mybatis.mybatis.session.Configuration;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;



/**
 * BaseStatementHandler 是一个抽象类，实现了 StatementHandler 接口。
 * 它为不同类型的 Statement 处理器提供了通用的基础实现，
 * 包含了配置信息、执行器、映射语句等核心属性，以及准备 Statement 对象的通用逻辑。
 */
public abstract class BaseStatementHandler implements StatementHandler {

    /**
     * MyBatis 的全局配置对象，包含了数据库连接、映射器等配置信息。
     */
    protected final Configuration configuration;
    /**
     * 执行 SQL 语句的执行器，负责与数据库进行交互。
     */
    protected final Executor executor;
    /**
     * 映射语句对象，封装了 SQL 语句的相关信息，如 SQL 语句、参数类型、返回类型等。
     */
    protected final MappedStatement mappedStatement;
    /**
     * SQL 语句的参数对象，用于传递给 SQL 语句。
     */
    protected final Object parameterObject;
    /**
     * 结果集处理器，负责处理数据库返回的结果集。
     */
    protected final ResultSetHandler resultSetHandler;
    /**
     * 绑定 SQL 对象，包含了最终要执行的 SQL 语句和参数映射信息。
     */
    protected BoundSql boundSql;

    /**
     * 构造函数，初始化 BaseStatementHandler 的各个属性。
     *
     * @param executor 执行 SQL 语句的执行器
     * @param mappedStatement 映射语句对象
     * @param parameterObject SQL 语句的参数对象
     * @param resultHandler 结果处理器（当前未使用）
     * @param boundSql 绑定 SQL 对象
     */
    public BaseStatementHandler(Executor executor, MappedStatement mappedStatement,
                                Object parameterObject, ResultSetHandler resultHandler, BoundSql boundSql) {
        // 从映射语句对象中获取配置信息
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.boundSql = boundSql;
        this.parameterObject = parameterObject;
        // 使用配置对象创建结果集处理器
        this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, boundSql);
    }

    /**
     * 准备用于执行 SQL 语句的 Statement 对象。
     * 该方法会调用抽象方法 instantiateStatement 实例化 Statement 对象，
     * 并设置查询超时时间和获取数据的大小。
     *
     * @param connection 数据库连接对象
     * @return 初始化后的 Statement 对象
     * @throws SQLException 当数据库操作出现异常时抛出
     */
    @Override
    public Statement prepare(Connection connection) throws SQLException {
        // 声明 Statement 对象
        Statement statement = null;
        try {
            // 调用抽象方法实例化 Statement 对象
            statement = instantiateStatement(connection);
            // 设置查询超时时间为 350 毫秒
            statement.setQueryTimeout(350);
            // 设置每次从数据库获取的数据量为 10000 条
            statement.setFetchSize(10000);
            return statement;
        } catch (Exception e) {
            // 若出现异常，抛出运行时异常并记录错误信息
            throw new RuntimeException("Error preparing statement.  Cause: " + e, e);
        }
    }

    /**
     * 抽象方法，用于实例化具体的 Statement 对象。
     * 不同的子类需要实现该方法，以创建不同类型的 Statement 对象，
     * 如 Statement、PreparedStatement 或 CallableStatement。
     *
     * @param connection 数据库连接对象
     * @return 实例化后的 Statement 对象
     * @throws SQLException 当数据库操作出现异常时抛出
     */
    public abstract Statement instantiateStatement(Connection connection) throws SQLException;
}